/*! Shopify WebMCP v0.1.0 - 5b357b96eca6cd702260d85b0d49de4598fad5e4 */ (function(){let e=[5,10,25,50,100,250,500,1e3,2500,5e3,1e4];function t(e){return Object.keys(e).toSorted().map(t=>`${t}\u0000${String(e[t])}`).join(``)}function n(e){return Object.entries(e).map(([e,t])=>({key:e,value:{stringValue:String(t)}}))}function r(e,t){for(let n=0;n{h=void 0,_()},u))}function ee(e,n,r={},i=`1`){if(!Number.isFinite(n))return;let a=`c\u0002${e}\u0002${i}\u0002${t(r)}`,o=p.get(a);o&&o.kind===`counter`?o.value+=n:p.set(a,{kind:`counter`,name:e,unit:i,attributes:r,value:n}),g()}function te(n,i,a={},o=`1`,s=e){if(!Number.isFinite(i))return;let c=`h\u0002${n}\u0002${o}\u0002${t(a)}`,l=p.get(c),u;l&&l.kind===`histogram`?u=l:(u={kind:`histogram`,name:n,unit:o,attributes:a,bounds:s,count:0,sum:0,min:i,max:i,bucketCounts:Array.from({length:s.length+1},()=>0)},p.set(c,u)),u.count+=1,u.sum+=i,u.min=Math.min(u.min,i),u.max=Math.max(u.max,i),u.bucketCounts[r(u.bounds,i)]+=1,g()}function _(){if(h!==void 0&&(clearTimeout(h),h=void 0),p.size===0)return;let e=d(),t=a(o,{name:c,version:l},p.values(),i(e),i(m));p.clear(),m=e;try{s(JSON.stringify(t),!0)}catch{}}return f&&typeof document<`u`&&typeof window<`u`&&typeof window.addEventListener==`function`&&(document.addEventListener(`visibilitychange`,()=>{document.visibilityState===`hidden`&&_()}),window.addEventListener(`pagehide`,()=>_())),{counter:ee,histogram:te,flush:_}}function s(e){return(t,n)=>{try{if(typeof fetch!=`function`)return;fetch(e,{method:`POST`,headers:{"Content-Type":`application/json`},body:t,keepalive:n}).catch(()=>{})}catch{}}}let c={localhost:!0,"127.0.0.1":!0,"0.0.0.0":!0,"[::1]":!0,"localtest.me":!0};function l(){if(typeof window>`u`||typeof document>`u`)return!1;let e=window.location?.host??``;return e!==``&&!c[e]&&!e.includes(`:`)}let u=null,d=!1;function f(){return d?u:(d=!0,l()&&(u=o({serviceName:`storefront_webmcp`,send:s(`https://otlp-http-production.shopifysvc.com/v1/metrics`),registerLifecycle:!0})),u)}function p(e,t=f()){if(!t)return;let{tool:n,durationMs:r,isError:i,errorClass:a}=e,o={tool_name:n,is_error:i,error_class:a??`none`};try{t.histogram(`webmcp_tool_call_duration_ms`,r,o,`ms`),t.counter(`webmcp_tool_call_total`,1,o),i&&t.counter(`webmcp_tool_call_errors_total`,1,{tool_name:n,error_class:a??`unknown`})}catch{}}function m(e){return typeof e==`object`&&!!e&&typeof Reflect.get(e,`then`)==`function`}function h(e){return e instanceof Error&&typeof e.name==`string`&&e.name.length>0?e.name:`Error`}function g(e){return typeof e==`object`&&!!e&&Reflect.get(e,`isError`)===!0}function ee(e,t,n=f()){return r=>{let i=performance.now(),a=(t,r)=>{p({tool:e,durationMs:performance.now()-i,isError:t,errorClass:r},n)};try{let e=t(r);if(m(e))return e.then(e=>{let t=g(e);return a(t,t?`tool_error`:void 0),e},e=>{throw a(!0,h(e)),e});let n=g(e);return a(n,n?`tool_error`:void 0),e}catch(e){throw a(!0,h(e)),e}}}let te={checkout:()=>_(`/checkout`),accountOrders:()=>_(`/account/orders`),product:e=>_(`/products/${e}`),collection:e=>_(`/collections/${e}`),search:e=>_(`/search?q=${encodeURIComponent(e)}`)};function _(e){return ne()+(e.startsWith(`/`)?e.slice(1):e)}function v(e){let t=re()?.match?.(e);if(t?.route===`product`||t?.route===`productInCollection`){let e=t.params?.productHandle;if(e)return e}let n=e.match(/\/products\/([^/?#]+)/);return n?.[1]?ie(n[1]):``}function ne(){if(typeof window>`u`)return`/`;let e=re()?.root;return typeof e==`string`?e:`/`}function re(){if(!(typeof window>`u`))return window.Shopify?.routes}function ie(e){try{return decodeURIComponent(e)}catch{return``}}let y={type:[`object`,`null`],properties:{type:`object`,properties:{amount:{type:`integer`},currency:{type:`string`}}}.properties},ae={type:`object`,properties:{name:{type:`string`},values:{type:`array`,items:{type:`string`}}}},b={type:`object`,properties:{name:{type:`string`},value:{type:`string`}}},oe={type:`object`,properties:{id:{type:`string`,description:`Storefront API Product GID. Pass as catalog.id to get_product.`},title:{type:`string`},handle:{type:`string`,description:`Product handle. Can be passed to update_cart as line_items[].handle.`},url:{type:`string`},price_range:y,image:{type:`string`},available:{type:`boolean`},variant_count:{type:`integer`},options:{type:`array`,description:`Product option names and possible values. These values do not guarantee every combination is purchasable; call get_product for available variants.`,items:ae},product_type:{type:`string`},vendor:{type:`string`}}},x={type:`object`,description:`Product + variant information for the line, sufficient to name and link to the item without an extra get_product call.`,properties:{id:{type:`string`,description:`Storefront API ProductVariant GID. Pass to update_cart as line_items[].item.id to add this variant.`},title:{type:`string`,description:`Product title (e.g. "Classic Hoodie").`},variant_title:{type:`string`,description:`Variant title (e.g. "Large / Black"). Empty or "Default Title" for single-variant products.`},handle:{type:`string`},url:{type:`string`,description:`Direct URL to the product page with the variant preselected.`},image:{type:`string`},unit_price:y}},se={type:`object`,properties:{id:{type:`string`,description:`Cart line GID from get_cart. Pass back to update_cart as line_items[].id to update or remove this line.`},item:x,quantity:{type:`integer`},line_price:{...y,description:`Total price for the line (quantity × unit_price).`}}},S={type:`object`,properties:{item:x,quantity:{type:`integer`,description:`Actual quantity on the cart line after the mutation. May differ from requested_quantity if the line merged with an existing entry or availability capped the add.`},requested_quantity:{type:`integer`,description:`Quantity the caller asked to add.`}}},ce={searchCatalog:{name:`search_catalog`,annotations:{readOnlyHint:!0,untrustedContentHint:!0},description:`Search the store catalog for products, collections, articles, and pages. Does NOT add anything to the cart; use update_cart for cart changes. If the user asks for a specific product variant, call get_product after search_catalog to inspect available variants, then show_variant to display one.`,inputSchema:{type:`object`,required:[`catalog`],properties:{catalog:{type:`object`,required:[`query`],properties:{query:{type:`string`,description:`Search query string.`},pagination:{type:`object`,properties:{limit:{type:`integer`,description:`Max results per type (1-10). Defaults to 5.`,default:5,minimum:1,maximum:10}}}}}}},outputSchema:{type:`object`,properties:{products:{type:`array`,items:oe},collections:{type:`array`},articles:{type:`array`},pages:{type:`array`},search_url:{type:`string`,description:`Full search results page URL.`}}}},browseStore:{name:`browse_store`,annotations:{readOnlyHint:!1,untrustedContentHint:!0},description:`Browse OR navigate to store collections. Set navigate=true whenever the user wants to be taken to a collection page in the browser (triggers: "browse to", "go to", "show me", "open", "take me to", "navigate to" a collection or category). With navigate=false (default), returns collection or product data without changing the page — use this only when the user is asking a question about the catalog, not asking to view it. Without a collection handle, lists all collections. With a handle, returns products from that collection; use "all" to browse everything. Does NOT add anything to the cart; use update_cart for cart changes. Prefer this over search_catalog when the user names a category, collection, or wants to explore. With navigate=true this MOVES the browser to the collection page; the tool result then confirms the destination and instructs you not to navigate again — follow it.`,inputSchema:{type:`object`,properties:{collection:{type:`string`,description:`Collection handle to browse (e.g. "best-sellers", "new-arrivals"). Omit to list all collections. Use "all" to browse every product.`},navigate:{type:`boolean`,description:`When true, navigate the browser to the collection page after loading data. Set true for user intents like "browse to", "go to", "show me", "open", "take me to" a collection. Requires a collection handle. Defaults to false.`},sort_by:{type:`string`,description:`Sort order. Options: best-selling (default), price-ascending, price-descending, title-ascending, title-descending, created-descending, created-ascending.`},page:{type:`number`,description:`Page number for pagination (starts at 1). Each page returns up to 30 products.`}}},outputSchema:{type:`object`,properties:{collections:{type:`array`,items:{type:`object`,properties:{title:{type:`string`},handle:{type:`string`},url:{type:`string`},description:{type:`string`}}}},products:{type:`array`,items:oe},collection_title:{type:`string`},page:{type:`number`},sort_by:{type:`string`},navigated:{type:`boolean`},url:{type:`string`}}}},getProduct:{name:`get_product`,annotations:{readOnlyHint:!1,untrustedContentHint:!0},description:`Get product details, OR navigate the browser to the product page. Set catalog.navigate=true whenever the user wants to see/view the product in the browser (triggers: "show me", "open", "view", "go to", "take me to", "navigate to" a product). Set catalog.navigate=false (default) only when you need data (description, options, variants, prices, availability) to answer a question or to prepare an update_cart call — the browser stays on the current page. Defaults to the current page's product if no catalog.id is provided. Does NOT add anything to the cart; use update_cart for that. For a specific variant (color/size/etc.), use show_variant instead — it accepts partial option selections like "purple" without needing every option. With catalog.navigate=true this MOVES the browser to the product page; the tool result then confirms the destination and instructs you not to navigate again — follow it.`,inputSchema:{type:`object`,properties:{catalog:{type:`object`,description:`Product detail parameters.`,properties:{id:{type:`string`,description:`Storefront API Product GID, product handle, or product URL path. Custom app product paths and Shopify standard /products/ paths are supported. The id field from search_catalog or browse_store can be passed directly. If omitted, uses the current page's product.`},navigate:{type:`boolean`,description:`When true, navigate the browser to the product page after fetching details. Set true for user intents like "show me", "open", "view", "go to", "take me to" a product. Defaults to false. If the user specified partial options (e.g. only a color), prefer show_variant with selected_options instead.`},selected_options:{type:`array`,description:`Known product option selections to filter available_options. Use exact option names and values from search_catalog options or a prior get_product available_options entry.`,items:{type:`object`,properties:{name:{type:`string`,description:`Option name, e.g. "Size" or "Color".`},value:{type:`string`,description:`Option value, e.g. "160cm" or "Fiberglass".`}},required:[`name`,`value`]}}}}}},outputSchema:{type:`object`,properties:{id:{type:`string`,description:`Storefront API Product GID.`},title:{type:`string`},handle:{type:`string`},description:{type:`object`,properties:{html:{type:`string`}}},vendor:{type:`string`},type:{type:`string`},tags:{type:`array`,items:{type:`string`}},url:{type:`string`},price_range:{type:`object`,properties:{min:y,max:y}},available:{type:`boolean`},options:{type:`array`,description:`All product option names and possible values. Use available_options to identify purchasable combinations.`,items:ae},variants:{type:`array`,description:`Resolved variant records. When catalog.selected_options contains a complete option combination, this contains the matching variant. Pass an available variant id to update_cart as line_items[].item.id.`,items:{type:`object`,properties:{id:{type:`string`,description:`Storefront API ProductVariant GID. Pass to show_variant as catalog.variant_id to display it, or update_cart as line_items[].item.id to add it.`},title:{type:`string`},options:{type:`array`,items:b},price:y,list_price:y,availability:{type:`object`,properties:{available:{type:`boolean`}}},sku:{type:`string`}}}},available_options:{type:`array`,description:`Available option combinations, optionally filtered by catalog.selected_options. Use one full combination to call get_product again when variants[] is empty.`,items:{type:`array`,items:b}},available_options_count:{type:`integer`,description:`Total available option combinations matching catalog.selected_options.`},available_options_truncated:{type:`boolean`,description:`True when more available option combinations exist than were returned.`},available_options_filter:{type:`array`,description:`The selected_options filter applied to available_options, when provided.`,items:b},images:{type:`array`,items:{type:`string`}}}}},showVariant:{name:`show_variant`,annotations:{readOnlyHint:!1},description:`Navigate the browser to a product page, with a specific variant OR a partial option filter selected. Use for view intents: "show me", "open", "view", "go to", "take me to" a specific product configuration. Accepts EITHER variant_id (fully specified variant) OR selected_options (partial, e.g. only Color=Purple) — with partial options the first matching available variant is picked automatically, so DO NOT ask the user for missing options when their intent is to view. Does NOT add anything to the cart; use update_cart for cart changes. For cart operations you still need a full variant_id — call get_product with the full option combination first. This MOVES the browser to the exact variant page with the variant pre-selected; the tool result then confirms the destination and instructs you not to navigate again — follow it.`,inputSchema:{type:`object`,required:[`catalog`],properties:{catalog:{type:`object`,description:`Provide EITHER variant_id OR selected_options. Handle is required unless the user is already on the product page.`,properties:{handle:{type:`string`,description:`Product handle. If omitted, uses the current product page's handle.`},variant_id:{type:[`string`,`number`],description:`ProductVariant ID from get_product variants[].id, e.g. "gid://shopify/ProductVariant/123", or the numeric variant ID. Use when the user picked a specific fully-specified variant. Omit when using selected_options.`},selected_options:{type:`array`,description:`Partial (or full) option selections, e.g. [{"name":"Color","value":"Purple"}]. Use when the user names some options but not all (e.g. "show me the purple shoe" — pass only Color). The first matching available variant will be selected automatically. Use exact option names and values from get_product available_options or search_catalog options.`,items:b}}}}},outputSchema:{type:`object`,properties:{handle:{type:`string`},variant_id:{type:`string`},url:{type:`string`},navigated:{type:`boolean`},selected_options:{type:`array`,description:`The option selections that were resolved to a variant, if provided.`,items:b}}}},getCart:{name:`get_cart`,annotations:{readOnlyHint:!0,untrustedContentHint:!0},description:`Get the current shopping cart contents — line items with product titles, variant titles, handles, URLs, images, unit prices, quantities, and totals. Everything needed to describe the cart to the user in natural language, without a follow-up get_product call per line. Works from any page.`,inputSchema:{type:`object`,properties:{}},outputSchema:{type:`object`,properties:{id:{type:`string`,description:`Cart GID.`},item_count:{type:`integer`},total_price:y,currency:{type:`string`},line_items:{type:`array`,items:se}}}},updateCart:{name:`update_cart`,annotations:{readOnlyHint:!1},description:`Add products to the cart, update line item quantities, or remove items. Batch EVERY change for one request into a SINGLE call — line_items accepts up to 10 entries; do NOT call update_cart once per item. Do NOT retry a call that already returned a result: adds are cumulative, so repeating a call adds duplicate items. Use line_items[].item.id with a ProductVariant GID when the exact variant is known. Use line_items[].id from get_cart to update or remove an existing line, passing the ABSOLUTE target quantity (not a delta; quantity 0 removes the line). Use handle or query only when adding the selected or first available variant.`,inputSchema:{type:`object`,required:[`cart`],properties:{cart:{type:`object`,required:[`line_items`],properties:{line_items:{type:`array`,description:`Items to add or update (1-10).`,items:{type:`object`,properties:{id:{type:`string`,description:`Existing cart line id from get_cart. Use to update or remove an existing line. Omit when adding new items.`},item:{type:`object`,description:`The merchandise to add.`,properties:{id:{type:`string`,description:`ProductVariant GID from get_product variants[].id, e.g. "gid://shopify/ProductVariant/123".`}}},handle:{type:`string`,description:`Product handle. Adds the selected or first available variant; call get_product first if the user requested specific options.`},query:{type:`string`,description:`Search query to find and add the selected or first available variant. For specific variants, call search_catalog/get_product first and pass item.id.`},quantity:{type:`integer`,description:`Quantity. Defaults to 1 for adds and updates. Set to 0 with an existing line id to remove it.`,default:1}}}}}}}},outputSchema:{type:`object`,properties:{updated:{type:`boolean`},deduped:{type:`boolean`,description:`True when this exact add was applied moments ago and was skipped to avoid a duplicate. When true, nothing changed on this call and updated is false.`},item_count:{type:`integer`},total_price:y,line_items:{type:`array`,description:`Items added by this mutation, with product/variant details filled in from the post-mutation cart.`,items:S},unresolved_items:{type:`array`},resolved_items:{type:`array`,description:`Present only on the clarification-needed path (nothing was applied). Items that could have been added, with pre-mutation lookup titles when available.`,items:S},warnings:{type:`array`,items:{type:`string`}}}}},cancelCart:{name:`cancel_cart`,annotations:{readOnlyHint:!1},description:`Remove all items from the cart in one step. Use when the user wants to empty their cart or start over.`,inputSchema:{type:`object`,properties:{}},outputSchema:{type:`object`,properties:{cleared:{type:`boolean`},previous_item_count:{type:`number`}}}},createCheckout:{name:`proceed_to_checkout`,annotations:{readOnlyHint:!1},description:`Proceed to checkout. Verifies the cart is not empty, then MOVES the browser to the checkout page. The tool result then confirms the destination and instructs you not to navigate again — follow it.`,inputSchema:{type:`object`,properties:{}},outputSchema:{type:`object`,properties:{navigating_to:{type:`string`},item_count:{type:`integer`},total_price:y}}},manageOrders:{name:`manage_orders`,annotations:{readOnlyHint:!1},description:`Navigate to the customer's order history page. Use when the user asks about past orders, order status, tracking, or returns. The user will be prompted to log in if not already authenticated. This MOVES the browser to the order history page; the tool result then confirms the destination and instructs you not to navigate again — follow it.`,inputSchema:{type:`object`,properties:{}}},searchShopPoliciesAndFaqs:{name:`search_shop_policies_and_faqs`,annotations:{readOnlyHint:!0,untrustedContentHint:!0},description:`Used to get facts about the store's policies, FAQ, or contact details. Some examples of questions you can ask are: - What is your return policy? - What is your shipping policy? - What is your phone number? - What are your hours of operation?" `,inputSchema:{type:`object`,properties:{query:{type:`string`,description:`A natural language query.`}},required:[`query`]},outputSchema:{type:`object`,properties:{policies:{type:`array`,description:`Store policies and contact information matching the query.`,items:{type:`object`,properties:{type:{type:`string`,description:`Policy kind: refund, shipping, privacy, terms_of_service, terms_of_sale, subscription, legal_notice, or contact.`},title:{type:`string`},url:{type:`string`},body:{type:`string`,description:`The policy text (may contain HTML).`}}}},pages:{type:`array`,description:`Store pages (e.g. FAQ, help) matching the query.`,items:{type:`object`,properties:{title:{type:`string`},handle:{type:`string`},url:{type:`string`},body:{type:`string`,description:`The page body (may contain HTML) for the top matched pages.`}}}},articles:{type:`array`,description:`Blog articles matching the query.`,items:{type:`object`,properties:{title:{type:`string`},handle:{type:`string`},url:{type:`string`},excerpt:{type:`string`}}}}}}}};function le(e){return e?e.startsWith(`v1_`)?ue(e.replace(/^v1_/,``)):(typeof console<`u`&&console.warn(`[hydrogen] Unsupported variant encoding: "${e}"`),[]):[]}function ue(e){let t=/[ :,-]/g,n={currentOptionValue:[],decodedOptions:[],depth:0,index:0,rangeStart:null},r;for(;r=t.exec(e);)de(e,n,r,t);return me(e,n),n.decodedOptions}function de(e,t,n,r){let i=n[0],a=Number.parseInt(e.slice(t.index,n.index),10)||0;he(t,a),t.currentOptionValue[t.depth]=a,i===`-`?t.rangeStart=a:i===`:`?t.depth++:fe(e,t,n,i),t.index=r.lastIndex}function fe(e,t,n,r){pe(e,n,r)&&t.decodedOptions.push([...t.currentOptionValue]),r===`,`&&(t.currentOptionValue.pop(),t.depth--)}function pe(e,t,n){return n===` `||n===`,`&&e[t.index-1]!==`,`}function me(e,t){let n=e.match(/\d+$/g)?.[0];if(n===void 0)return;let r=Number.parseInt(n,10);if(t.rangeStart!==null){he(t,r+1);return}t.currentOptionValue[t.depth]=r,t.decodedOptions.push([...t.currentOptionValue])}function he(e,t){let n=e.rangeStart;if(n!==null){for(let r=n;r{let n=e;if(t){let e=new Set;for(let r of t)e.has(r)||(e.add(r),n+=` `+r)}return n}),w=(e,t,n,r)=>{let i=e;return n&&(i+=`\n\n${n}`),r&&(i+=`\n\nNext steps: ${r}`),{content:[{type:`text`,text:i}],structuredContent:t}},T=(e,t,n)=>({content:[{type:`text`,text:`Suggested response: ${e}${n?`\n\n${n}`:``}\n\nNow respond to the user with a friendly message. If you completed multiple steps, recap the full journey.`}],structuredContent:t}),E=(e,t)=>{let{summary:n,navigated:r,destination:i,keyFields:a}=e,o=i?`the ${i} page`:`the requested page`,s=`${r?`Navigation is complete: the browser is ALREADY on ${o} and the user is looking at it now.`:`The browser is ALREADY on ${o} and the user is looking at it now — no navigation was needed.`}\n\nDo NOT navigate again by ANY means for this request: not with another webmcp tool (browse_store, get_product navigate=true, show_variant, proceed_to_checkout, manage_orders), not with any host tool that changes the page URL / opens / loads / fetches a page (whatever its name), and not by constructing, guessing, or retyping a URL yourself. Do NOT tell the user to click a link or button or open a URL — they are already there. The destination is confirmed; just reply, referring to the page by name.\n\nSuggested reply: ${n}`;return a&&(s+=`\n\n${a}`),{content:[{type:`text`,text:s}],structuredContent:t}},D=(e,t)=>{let n=`Error: ${e}`;return t&&(n+=`\nRecovery: ${t}`),{content:[{type:`text`,text:n}],structuredContent:{error:e},isError:!0}},O=()=>{let e=window.Shopify?.actions;if(!e?.getCart||!e.updateCart)throw Error(`Standard Actions are not available. Ensure Shopify Standard Actions are available before calling cart tools.`);return e},k=async(e=O())=>(await e.getCart()).cart??{},ge=e=>{let t=e.userErrors?.map(e=>e.message).filter(Boolean);if(t?.length)throw Error(t.join(`, `))},_e=e=>e.warnings?.map(e=>e.message).filter(F)??[],ve=e=>e.lines?.nodes??[],A=e=>e.totalQuantity??0,j=new Map,M=e=>{let t=String(e??``).toUpperCase();if(!t)return 2;let n=j.get(t);if(n!=null)return n;try{let e=new Intl.NumberFormat(`en`,{style:`currency`,currency:t}).resolvedOptions().maximumFractionDigits??2;return j.set(t,e),e}catch{return 2}},N=e=>{if(e?.amount==null||!e.currencyCode)return null;let t=Number(e.amount);return Number.isFinite(t)?{amount:Math.round(t*10**M(e.currencyCode)),currency:e.currencyCode}:null},P=e=>{if(!e)return``;let t=M(e.currency),n=e.amount/10**t;try{return new Intl.NumberFormat(`en-US`,{style:`currency`,currency:e.currency}).format(n)}catch{return`${n.toFixed(t)} ${e.currency}`}},F=e=>typeof e==`string`&&e.length>0,I=C(`fragment WebMcpMoney on MoneyV2{amount currencyCode}`),L=C(`fragment WebMcpProductCard on Product{id title handle vendor productType availableForSale onlineStoreUrl featuredImage{url altText}priceRange{minVariantPrice{...WebMcpMoney}}variantsCount{count}options{name values}}`,[I]),R=C(`fragment WebMcpProductForCart on Product{title handle selectedOrFirstAvailableVariant{id title availableForSale}}`),ye=C(`fragment WebMcpCartDetails on Cart{id totalQuantity cost{totalAmount{...WebMcpMoney}}lines(first:250){nodes{id quantity cost{totalAmount{...WebMcpMoney}}merchandise{__typename ...on ProductVariant{id title image{url altText}price{...WebMcpMoney}product{id title handle onlineStoreUrl}}}}}}`,[I]),z=C(`fragment WebMcpProductDetails on Product{id title handle descriptionHtml vendor productType tags availableForSale onlineStoreUrl featuredImage{url altText}priceRange{minVariantPrice{...WebMcpMoney}maxVariantPrice{...WebMcpMoney}}variantsCount{count}encodedVariantAvailability selectedOrFirstAvailableVariant{...WebMcpProductVariant}options{name values}images(first:20){nodes{url altText}}}`,[C(`fragment WebMcpProductVariant on ProductVariant{id title availableForSale sku price{...WebMcpMoney}compareAtPrice{...WebMcpMoney}selectedOptions{name value}}`,[I])]),be=C(`query WebMcpSearchCatalog($query:String!$types:[PredictiveSearchType!]$limit:Int!){predictiveSearch(query:$query types:$types limit:$limit){products{...WebMcpProductCard}collections{title handle description onlineStoreUrl}articles{title handle excerpt onlineStoreUrl}pages{title handle onlineStoreUrl}}}`,[L]),xe=C(`query WebMcpSearchPoliciesAndFaqs($query:String!$types:[PredictiveSearchType!]$limit:Int!$includeRefund:Boolean!$includeShipping:Boolean!$includePrivacy:Boolean!$includeTermsOfService:Boolean!$includeTermsOfSale:Boolean!$includeSubscription:Boolean!$includeLegalNotice:Boolean!$includeContact:Boolean!){shop{refundPolicy@include(if:$includeRefund){title body url}shippingPolicy@include(if:$includeShipping){title body url}privacyPolicy@include(if:$includePrivacy){title body url}termsOfService@include(if:$includeTermsOfService){title body url}termsOfSale@include(if:$includeTermsOfSale){title body url}subscriptionPolicy@include(if:$includeSubscription){title body url}legalNotice@include(if:$includeLegalNotice){title body url}contactInformation@include(if:$includeContact){title body url}}predictiveSearch(query:$query types:$types limit:$limit){articles{title handle excerpt onlineStoreUrl}pages{title handle onlineStoreUrl}}}`),Se=C(`query WebMcpPageBodies($h1:String$h2:String$h3:String){p1:page(handle:$h1){title body}p2:page(handle:$h2){title body}p3:page(handle:$h3){title body}}`),Ce=C(`query WebMcpListCollections($first:Int!){collections(first:$first){nodes{title handle description onlineStoreUrl}}}`),we=C(`query WebMcpBrowseProducts($first:Int!$sortKey:ProductSortKeys$reverse:Boolean!){products(first:$first sortKey:$sortKey reverse:$reverse){nodes{...WebMcpProductCard}}}`,[L]),Te=C(`query WebMcpBrowseCollectionProducts($handle:String!$first:Int!$sortKey:ProductCollectionSortKeys$reverse:Boolean!){collection(handle:$handle){title handle description onlineStoreUrl products(first:$first sortKey:$sortKey reverse:$reverse){nodes{...WebMcpProductCard}}}}`,[L]),Ee=C(`query WebMcpProductByHandle($handle:String!$selectedOptions:[SelectedOptionInput!]!$hasSelectedOptions:Boolean!){product(handle:$handle){...WebMcpProductDetails variantBySelectedOptions(selectedOptions:$selectedOptions caseInsensitiveMatch:true)@include(if:$hasSelectedOptions){...WebMcpProductVariant}}}`,[z]),De=C(`query WebMcpProductById($id:ID!$selectedOptions:[SelectedOptionInput!]!$hasSelectedOptions:Boolean!){node(id:$id){__typename ...on Product{...WebMcpProductDetails variantBySelectedOptions(selectedOptions:$selectedOptions caseInsensitiveMatch:true)@include(if:$hasSelectedOptions){...WebMcpProductVariant}}}}`,[z]),Oe=C(`query WebMcpProductForCartByHandle($handle:String!){product(handle:$handle){...WebMcpProductForCart}}`,[R]),ke=C(`query WebMcpCartDetails($id:ID!){cart(id:$id){...WebMcpCartDetails}}`,[ye]),Ae=C(`query WebMcpSearchProductForCart($query:String!){predictiveSearch(query:$query types:[PRODUCT]limit:1){products{...WebMcpProductForCart}}}`,[R]);async function je(e,t){return{predictiveSearch:Ge((await H(be,{query:e,types:[`PRODUCT`,`COLLECTION`,`ARTICLE`,`PAGE`],limit:t})).predictiveSearch)}}let B=[{type:`refund`,field:`refundPolicy`,include:`includeRefund`},{type:`shipping`,field:`shippingPolicy`,include:`includeShipping`},{type:`privacy`,field:`privacyPolicy`,include:`includePrivacy`},{type:`terms_of_service`,field:`termsOfService`,include:`includeTermsOfService`},{type:`terms_of_sale`,field:`termsOfSale`,include:`includeTermsOfSale`},{type:`subscription`,field:`subscriptionPolicy`,include:`includeSubscription`},{type:`legal_notice`,field:`legalNotice`,include:`includeLegalNotice`},{type:`contact`,field:`contactInformation`,include:`includeContact`}],Me=B.map(e=>e.type);async function Ne(e,t,n){let r=new Set(n),i=await H(xe,{query:e,types:[`ARTICLE`,`PAGE`],limit:t,includeRefund:r.has(`refund`),includeShipping:r.has(`shipping`),includePrivacy:r.has(`privacy`),includeTermsOfService:r.has(`terms_of_service`),includeTermsOfSale:r.has(`terms_of_sale`),includeSubscription:r.has(`subscription`),includeLegalNotice:r.has(`legal_notice`),includeContact:r.has(`contact`)}),a=(i.predictiveSearch?.pages??[]).map(gt),o=(i.predictiveSearch?.articles??[]).map(ht);return{policies:Pe(i.shop),articles:o,pages:await Fe(a)}}function Pe(e){return e?B.flatMap(({type:t,field:n})=>{let r=e[n];return r?[{type:t,title:r.title??``,url:r.url??``,body:r.body??``}]:[]}):[]}async function Fe(e){let t=e.filter(e=>e.handle).slice(0,3);if(!t.length)return e;let n=t.map(e=>e.handle),r=await H(Se,{h1:n[0]??null,h2:n[1]??null,h3:n[2]??null}),i=[r.p1,r.p2,r.p3],a=new Map;return t.forEach((e,t)=>{let n=i[t]?.body;n&&a.set(e.handle,n)}),e.map(e=>{let t=a.get(e.handle);return t?{...e,body:t}:e})}async function Ie(){return{collections:{nodes:(await H(Ce,{first:50})).collections?.nodes?.map(W)??[]}}}async function Le(e){return{products:He((await H(we,{first:Ve(e.page),...Ue(e.sortBy)})).products?.nodes??[],e.page).map(U),title:`All products`}}async function Re(e){let t=e.handle.trim(),n=await H(Te,{handle:t,first:Ve(e.page),...We(e.sortBy)}),r=n.collection?W(n.collection):null;return{collection:r,products:He(n.collection?.products?.nodes??[],e.page).map(U),title:r?.title??t}}async function V(e,t){let n=_t(e);if(!n)return null;let r=ft(t.selected_options),i=r.length>0;if(vt(n)){let e=(await H(De,{id:n,selectedOptions:r,hasSelectedOptions:i})).node;return e?.__typename===`Product`?ot(U(e),t):null}let a=await H(Ee,{handle:n,selectedOptions:r,hasSelectedOptions:i});return a.product?ot(U(a.product),t):null}async function ze(e,t){let n=e.trim();if(!n)return null;let r=(await H(ke,{id:n})).cart;return r?{id:r.id??n,item_count:r.totalQuantity??0,total_price:N(r.cost?.totalAmount),currency:r.cost?.totalAmount?.currencyCode??``,line_items:(r.lines?.nodes??[]).map(e=>Ke(e,t))}:null}async function Be(e){if(e.handle?.trim()){let t=await H(Oe,{handle:e.handle.trim()});return t.product?Ze(t.product):null}if(e.query?.trim()){let t=(await H(Ae,{query:e.query.trim()})).predictiveSearch?.products?.[0];return t?Ze(t):null}return null}async function H(e,t){let n=await fetch(`/api/2026-04/graphql.json`,{method:`POST`,headers:{accept:`application/json`,"content-type":`application/json`},body:JSON.stringify({query:e,variables:t})});if(!n.ok)throw Error(`Storefront API request failed (${n.status})`);let r=await n.json();if(r.errors?.length)throw Error(r.errors.map(e=>e.message).filter(Boolean).join(`, `));if(!r.data)throw Error(`Storefront API response did not include data.`);return r.data}function Ve(e){return Math.min(Math.max(1,e)*30,250)}function He(e,t){let n=(Math.max(1,t)-1)*30;return e.slice(n,n+30)}function Ue(e){switch(e){case`price-ascending`:return{sortKey:`PRICE`,reverse:!1};case`price-descending`:return{sortKey:`PRICE`,reverse:!0};case`title-ascending`:return{sortKey:`TITLE`,reverse:!1};case`title-descending`:return{sortKey:`TITLE`,reverse:!0};case`created-ascending`:return{sortKey:`CREATED_AT`,reverse:!1};case`created-descending`:return{sortKey:`CREATED_AT`,reverse:!0};default:return{sortKey:`BEST_SELLING`,reverse:!1}}}function We(e){switch(e){case`price-ascending`:return{sortKey:`PRICE`,reverse:!1};case`price-descending`:return{sortKey:`PRICE`,reverse:!0};case`title-ascending`:return{sortKey:`TITLE`,reverse:!1};case`title-descending`:return{sortKey:`TITLE`,reverse:!0};case`created-ascending`:return{sortKey:`CREATED`,reverse:!1};case`created-descending`:return{sortKey:`CREATED`,reverse:!0};default:return{sortKey:`BEST_SELLING`,reverse:!1}}}function Ge(e){return{products:(e?.products??[]).map(U),collections:(e?.collections??[]).map(W),articles:(e?.articles??[]).map(rt),pages:(e?.pages??[]).map(it)}}function U(e){let t=e.selectedOrFirstAvailableVariant?tt(e.selectedOrFirstAvailableVariant):null,n=e.variantBySelectedOptions?tt(e.variantBySelectedOptions):null;return{id:e.id,title:e.title,handle:e.handle,descriptionHtml:e.descriptionHtml,vendor:e.vendor,productType:e.productType,tags:e.tags,availableForSale:e.availableForSale,onlineStoreUrl:e.onlineStoreUrl,featuredImage:e.featuredImage??null,priceRange:e.priceRange,variantCount:e.variantsCount?.count??0,selectedOrFirstAvailableVariant:t,variantBySelectedOptions:n,encodedVariantAvailability:e.encodedVariantAvailability,options:Qe(e.options),images:et(e.images?.nodes)}}function Ke(e,t){return{id:e.id??``,quantity:e.quantity??0,line_price:N(e.cost?.totalAmount),item:qe(e,t)}}function qe(e,t){let n=Je(e),r=n.product;return{id:n.id,title:r.title,variant_title:n.title,handle:r.handle,url:Xe({handle:r.handle,onlineStoreUrl:r.onlineStoreUrl},n.id,t),image:n.image,unit_price:N(n.price)}}function Je(e){let t=e.merchandise,n=t?.__typename===`ProductVariant`?t:null;return{id:n?.id??``,title:n?.title??``,image:n?.image?.url??``,price:n?.price,product:Ye(n?.product)}}function Ye(e){return{id:e?.id??``,title:e?.title??``,handle:e?.handle??``,onlineStoreUrl:e?.onlineStoreUrl}}function Xe(e,t,n){let r=q(e,e=>n.product(e));if(!r)return``;let i=t.split(`/`).pop();return i?`${r}${r.includes(`?`)?`&`:`?`}variant=${encodeURIComponent(i)}`:r}function Ze(e){let t=e.selectedOrFirstAvailableVariant;return!t?.id||!t.availableForSale?null:{product:{title:e.title,handle:e.handle},variant:{merchandise_id:t.id,title:t.title}}}function Qe(e){return e?.map(e=>({name:e.name??``,values:e.values??[]}))??[]}function $e(e){return e?.map(e=>({name:e.name??``,value:e.value??``}))??[]}function et(e){return e?.filter(nt)??[]}function tt(e){return{id:e.id??``,title:e.title??``,availableForSale:!!e.availableForSale,price:e.price,compareAtPrice:e.compareAtPrice,sku:e.sku,selectedOptions:$e(e.selectedOptions)}}function nt(e){return e!=null}function W(e){return{title:e.title,handle:e.handle,description:e.description,onlineStoreUrl:e.onlineStoreUrl}}function rt(e){return{title:e.title,handle:e.handle,excerpt:e.excerpt,onlineStoreUrl:e.onlineStoreUrl}}function it(e){return{title:e.title,handle:e.handle,onlineStoreUrl:e.onlineStoreUrl}}function G(e,t){let n=yt(e);return{id:e.id??``,title:e.title??``,handle:n,url:at(e,n,t),price_range:N(e.priceRange?.minVariantPrice),image:xt(e.featuredImage),available:!!e.availableForSale,variant_count:e.variantCount??0,options:e.options??[],product_type:e.productType??``,vendor:e.vendor??``}}function at(e,t,n){return q({handle:t,onlineStoreUrl:e.onlineStoreUrl},e=>n.product(e))}function ot(e,t){let n=G(e,t.routes),r=e.options??[],i=ft(t.selected_options),a=ct(r,e,i),o=st(e,i);return{...n,description:{html:e.descriptionHtml??``},type:e.productType??``,tags:e.tags??[],price_range:{min:N(e.priceRange?.minVariantPrice),max:N(e.priceRange?.maxVariantPrice)},variants:o.map(pt),available_options:a.options,available_options_count:a.count,available_options_truncated:a.truncated,available_options_filter:i.length?i:void 0,images:e.images?.map(xt).filter(F)??[]}}function st(e,t){return t.length?e.variantBySelectedOptions?[e.variantBySelectedOptions]:[]:e.selectedOrFirstAvailableVariant?[e.selectedOrFirstAvailableVariant]:[]}function ct(e,t,n){let r=le(t.encodedVariantAvailability),i=[];for(let t of r){let r=lt(e,t);r&&ut(r,n)&&i.push(r)}let a=n.length>0||i.length<=50?i.slice(0,50):[];return{options:a,count:i.length,truncated:i.length>a.length}}function lt(e,t){if(!e.length||t.length!==e.length)return null;let n=[];for(let[r,i]of e.entries()){let e=i.values[t[r]];if(!e)return null;n.push({name:i.name,value:e})}return n}function ut(e,t){return t.every(t=>e.some(e=>dt(e,t)))}function dt(e,t){return K(e.name)===K(t.name)&&K(e.value)===K(t.value)}function ft(e){return e?.map(e=>({name:e.name?.trim()??``,value:e.value?.trim()??``})).filter(e=>e.name&&e.value)??[]}function K(e){return e?.trim().toLowerCase()??``}function pt(e){return{id:e.id??``,title:e.title??``,options:e.selectedOptions??[],price:N(e.price),list_price:N(e.compareAtPrice),availability:{available:!!e.availableForSale},sku:e.sku??void 0}}function mt(e,t){let n=e.handle??``;return{title:e.title??``,handle:n,url:q(e,e=>t.collection(e)),description:e.description??``}}function ht(e){return{title:e.title??``,handle:e.handle??``,url:q(e),excerpt:e.excerpt??``}}function gt(e){return{title:e.title??``,handle:e.handle??``,url:q(e)}}function q(e,t){let n=bt(e.onlineStoreUrl);if(n)return n;let r=e.handle?.trim();return r?t?.(r)??``:``}function _t(e){let t=e?.trim();return t?v(t)||t:``}function vt(e){return e.startsWith(`gid://shopify/Product/`)}function yt(e){return e.handle??v(bt(e.onlineStoreUrl))}function bt(e){if(!e)return``;if(e.startsWith(`/`))return e;try{let t=new URL(e);return e.replace(t.origin,``)}catch{return e}}function xt(e){return e?.url??``}let St=new Set([`best-selling`,`price-ascending`,`price-descending`,`title-ascending`,`title-descending`,`created-ascending`,`created-descending`]),Ct=async(e,t)=>{try{let n=e.collection?.trim(),r=e.navigate===!0;if(!n)return Tt(await Ie(),t.routes,r);let i=Math.max(1,Number(e.page)||1),a=Ot(e.sort_by);return Et(n,await wt(n,a,i),a,i,t,r)}catch(e){return D(e instanceof Error?e.message:`Failed to browse store`,`Try browsing without a collection to list available collections.`)}};async function wt(e,t,n){return e===`all`?Le({page:n,sortBy:t}):Re({handle:e,page:n,sortBy:t})}function Tt(e,t,n){let r=e.collections?.nodes?.map(e=>mt(e,t))??[],i=n?`A collection handle is required to navigate. Ask the user which collection, or call browse_store again with a specific collection handle (or "all") and navigate=true.`:`Call browse_store with a collection handle, or with collection "all" to browse products. Set navigate=true to take the user to the collection page.`;return w(`Found ${r.length} collection${r.length===1?``:`s`}.`,{collections:r,products:[],navigated:!1},kt(r),i)}function Et(e,t,n,r,i,a){let{routes:o}=i;if(e!==`all`&&!t.collection)return D(`Collection "${e}" was not found.`,`Call browse_store without a collection to list available collections.`);let s=t.products.map(e=>G(e,o)),c=o.collection(e),l={collections:[],products:s,collection_title:t.title,page:r,sort_by:n,url:c};if(a){let e=!Dt(c);return e&&setTimeout(()=>i.navigate(c),0),E({summary:e?`Showing the ${t.title} collection.`:`Already showing the ${t.title} collection.`,navigated:e,destination:`${t.title} collection`,keyFields:At(s)},{...l,navigated:e})}return w(`Showing ${s.length} product${s.length===1?``:`s`} from ${t.title}.`,{...l,navigated:!1},At(s),`If the user asked to be taken to this collection, call browse_store again with navigate=true. If the user wants the selected or first available variant, call update_cart with cart.line_items using the product handle. If the user requested a specific color, size, material, or other option, call get_product with catalog.id and any known catalog.selected_options, then use the matching variants[].id with update_cart, OR call show_variant with selected_options to just navigate to that variant.`)}function Dt(e){if(typeof window>`u`)return!1;let t=new URL(window.location.href);return t.pathname+t.search===e}function Ot(e){return e&&St.has(e)?e:`best-selling`}function kt(e){return e.length?`Collections:\n${e.map(e=>`- ${e.title} (${e.handle})`).join(` `)}`:null}function At(e){return e.length?`Products:\n${e.map(e=>`- ${e.title} (id: ${e.id}, handle: ${e.handle}) - ${P(e.price_range)||`price unavailable`}`).join(` `)}`:null}let jt=async()=>{try{let e=O(),t=await k(e),n=A(t);if(n===0)return T(`Cart is already empty.`,{cleared:!0,previous_item_count:0});let r=ve(t).filter(e=>e.id).map(e=>({id:e.id,quantity:0})),i=await e.updateCart({lines:r});ge(i);let a=_e(i),o=a.length?` Warnings: ${a.join(`; `)}.`:``;return T(`Cart cleared. Removed ${n} item${n===1?``:`s`}.${o}`,{cleared:!0,previous_item_count:n,...a.length&&{warnings:a}},`The cart has ALREADY been emptied — this result is the authoritative state. Do NOT call cancel_cart or update_cart again for this request.`)}catch(e){return D(e instanceof Error?e.message:`Failed to clear cart`,`Try update_cart with each line_items[].id and quantity 0 to remove items individually.`)}},Mt=async(e,t)=>{try{let e=await k(),n=A(e);if(n===0)return D(`Cart is empty. Add items before checking out.`,`Use search_catalog or update_cart to add products first.`);let r=N(e.cost?.totalAmount),i=t.routes.checkout(),a=!Nt(i);a&&setTimeout(()=>t.navigate(i),0);let o=r?` totaling ${P(r)}`:``;return E({summary:a?`Taken you to checkout with ${n} item${n===1?``:`s`}${o}.`:`Already on the checkout page with ${n} item${n===1?``:`s`}${o}.`,navigated:a,destination:`checkout`},{navigating_to:i,item_count:n,total_price:r})}catch(e){return D(e instanceof Error?e.message:`Failed to initiate checkout`,`Call get_cart to verify cart contents, then retry.`)}};function Nt(e){if(typeof window>`u`)return!1;let t=new URL(window.location.href);return t.pathname+t.search===e}let Pt=async(e,t)=>{try{let e=await k();return(e.totalQuantity??0)===0||!e.id?Ft(e):It(await ze(e.id,t.routes)||Vt(e,t.routes))}catch(e){return D(e instanceof Error?e.message:`Failed to fetch cart`,`Try again - this is usually a transient error.`)}},Ft=e=>w(`Cart is empty.`,{id:e.id??``,item_count:0,total_price:N(e.cost?.totalAmount),currency:e.cost?.totalAmount?.currencyCode??``,line_items:[]},null,`Use search_catalog or browse_store to help the user find products to add. Then call update_cart with cart.line_items.`),It=e=>w(Lt(e),e,Rt(e.line_items),`To modify quantities, call update_cart with the line_items[].id from this response and the new quantity. To remove an item, call update_cart with quantity 0. To proceed, use proceed_to_checkout.`),Lt=e=>{let t=e.line_items.slice(0,3).map(Bt).join(`, `),n=e.line_items.length>3?` and ${e.line_items.length-3} more`:``,r=e.item_count===1?``:`s`,i=P(e.total_price)||`unknown total`;return`Cart has ${e.item_count} item${r} totaling ${i}: ${t}${n}.`},Rt=e=>`Cart line items: `+e.map(zt).join(` `),zt=e=>{let t=P(e.line_price)||`price unavailable`;return`- ${e.id}: "${Bt(e)}" - ${t}`},Bt=e=>{let t=e.item.title||e.item.handle||e.item.id||`item`,n=e.item.variant_title;return`${t}${n&&n!==`Default Title`?` (${n})`:``} x${e.quantity}`};function Vt(e,t){return{id:e.id??``,item_count:e.totalQuantity??0,total_price:N(e.cost?.totalAmount),currency:e.cost?.totalAmount?.currencyCode??``,line_items:(e.lines?.nodes??[]).map(e=>({id:e.id??``,quantity:e.quantity??0,line_price:N(e.cost?.totalAmount),item:{id:``,title:``,variant_title:``,handle:``,url:``,image:``,unit_price:null}}))}}let Ht=async(e,t)=>{let n=e.catalog,r=_t(n?.id)||Jt();if(!r)return D(`Product catalog.id is required.`,`Call search_catalog or browse_store to find a product id or handle first.`);try{return await Ut(r,n,t)}catch(e){return D(e instanceof Error?e.message:`Failed to load product details`,`Try again with a product id or handle from search_catalog or browse_store.`)}};async function Ut(e,t,n){let r=t?.selected_options,i=r?.length?[...r]:void 0,a=await V(e,{selected_options:i,routes:n.routes});return a?t?.navigate===!0?Gt(a,n):qt(a,!!i?.length):Wt(e)}function Wt(e){return D(`Product "${e}" was not found.`,`Call search_catalog or browse_store to find an available product.`)}function Gt(e,t){let n=e.url,r=!Kt(n);return r&&setTimeout(()=>t.navigate(n),0),E({summary:r?`Showing ${e.title}.`:`Already showing ${e.title}.`,navigated:r,destination:e.title},e)}function Kt(e){if(typeof window>`u`)return!1;let t=new URL(window.location.href);return t.pathname+t.search===e}function qt(e,t){return w(`${e.title} has ${e.variant_count} variant${e.variant_count===1?``:`s`}.`,e,Yt(e),Xt(e,t))}function Jt(){return typeof window>`u`?``:v(window.location.href)}function Yt(e){if(!e.variants.length)return null;let t=e.variants.filter(e=>e.availability.available);return`Variants: `+(t.length?t:e.variants.slice(0,10)).map(e=>{let t=e.options.map(e=>`${e.name}: ${e.value}`).join(`, `),n=P(e.price)||`price unavailable`,r=e.availability.available?`available`:`unavailable`;return`- ${e.title} (id: ${e.id}) - ${t||`no options`} - ${n} - ${r}`}).join(` `)}function Xt(e,t){let n=e.variants.filter(e=>e.availability.available),r=`TO VIEW (show/open/go to): call show_variant with catalog.selected_options set to whatever options the user specified (even partial like just Color) — do NOT ask for missing options.`;return n.length&&t?`${r} TO ADD TO CART: use the matching variants[].id from this result with update_cart line_items[].item.id.`:n.length?`${r}${e.available_options_truncated?` (available_options is truncated — narrow with catalog.selected_options if needed).`:``} TO ADD TO CART: if the user did not request specific options, use variants[0].id or the product handle with update_cart. If they requested specific options, pick one complete available_options entry (or call get_product again with catalog.selected_options) to get the exact variants[].id.`:e.available_options_count>0?`${r} TO ADD TO CART: you need a full option combination — pick one complete available_options entry, or ask the user for missing options, then call get_product again with catalog.selected_options set to that full combination to get the exact variants[].id.`:e.available_options_truncated?`Available option combinations were truncated. Call get_product again with catalog.selected_options for any options the user already specified to narrow the result before choosing a variant.`:`No available option combinations matched. Ask the user to choose different product options or search for another product.`}let Zt=(e,t)=>{let n=t.routes.accountOrders(),r=!Qt(n);return r&&setTimeout(()=>t.navigate(n),10),E({summary:r?`Taken you to your order history. You may need to log in if not already authenticated.`:`Already on your order history page. You may need to log in if not already authenticated.`,navigated:r,destination:`order history`},{navigating_to:n})};function Qt(e){if(typeof window>`u`)return!1;let t=new URL(window.location.href);return t.pathname+t.search===e}let $t=async(e,t)=>{let n=e.catalog?.query?.trim();if(!n)return D(`Search query is required.`,`Call search_catalog with catalog.query.`);try{return tn(n,en((await je(n,sn(Number(e.catalog?.pagination?.limit)||5,1,10))).predictiveSearch,t.routes),t.routes)}catch(e){return D(e instanceof Error?e.message:`Search failed`,`Try again with a simpler catalog.query, or use browse_store to inspect collections.`)}};function en(e,t){return{products:e.products.map(e=>G(e,t)),collections:e.collections.map(e=>mt(e,t)),articles:e.articles.map(ht),pages:e.pages.map(gt)}}function tn(e,t,n){let r=t.products.length+t.collections.length+t.articles.length+t.pages.length,i={...t,search_url:n.search(e)};return r===0?w(`No search results found for "${e}".`,i,null,`Try browse_store to inspect collections or search_catalog with a broader catalog.query.`):w(`Found ${nn(t).join(`, `)} for "${e}".`,i,an(t),rn(t))}function nn(e){return[J(`product`,e.products.length),J(`collection`,e.collections.length),J(`article`,e.articles.length),J(`page`,e.pages.length)].filter(Boolean)}function J(e,t){return t?`${t} ${e}${t===1?``:`s`}`:``}function rn(e){return e.products.length?`If the user wants the selected or first available variant, call update_cart with cart.line_items using the product handle or query. If the user requested a specific color, size, material, or other option, call get_product with catalog.id and any known catalog.selected_options to filter available_options, then use the matching variants[].id with update_cart.`:e.collections.length||e.articles.length||e.pages.length?`No products matched, but other catalog results were found. Share the relevant collection, article, or page URL with the user, or call browse_store for product collections.`:`Use browse_store to inspect products by collection.`}function an(e){let t=[on(e.products),Y(`Collections`,e.collections),Y(`Articles`,e.articles),Y(`Pages`,e.pages)].filter(Boolean);return t.length?t.join(` `):null}function on(e){return e.length?`Products: `+e.map(e=>`- ${e.title} (id: ${e.id}, handle: ${e.handle}) - ${P(e.price_range)||`price unavailable`}`).join(` `):null}function Y(e,t){return t.length?`${e}:\n`+t.map(e=>`- ${e.title}${e.handle?` (${e.handle})`:``}: ${e.url}`).join(` `):null}function sn(e,t,n){return Math.min(n,Math.max(t,e))}let cn=[{type:`refund`,patterns:[/\brefund/i,/\breturn/i,/\bmoney\s+back/i,/\bexchange/i,/\breimburse/i]},{type:`shipping`,patterns:[/\bship/i,/\bdeliver/i,/\bdispatch/i,/\bfulfil/i,/\bfulfill/i,/\bpostage/i,/\btracking/i,/\bcourier/i]},{type:`privacy`,patterns:[/\bprivacy/i,/\bdata/i,/\bcookie/i,/\bgdpr/i,/\bpersonal\s+information/i,/\bpersonal\s+data/i]},{type:`terms_of_service`,patterns:[/\bterms\s+of\s+service/i,/\bterms\s+of\s+use/i,/\btos/i,/\bterms/i]},{type:`terms_of_sale`,patterns:[/\bterms\s+of\s+sale/i,/\bpurchase\s+terms/i]},{type:`subscription`,patterns:[/\bsubscription/i,/\bsubscribe/i,/\brecurring/i]},{type:`legal_notice`,patterns:[/\blegal\s+notice/i,/\bimprint/i,/\bcompany\s+info/i]},{type:`contact`,patterns:[/\bphone/i,/\bcall/i,/\bcontact/i,/\bemail/i,/\baddress/i,/\bhours/i,/\bopening/i,/\blocation/i,/\breach/i,/\bsupport/i]}],ln=async e=>{let t=e.query?.trim();if(!t)return D(`A search query is required.`,`Call search_shop_policies_and_faqs with a query, e.g. 'return policy' or 'shipping'.`);try{let e=await Ne(t,5,un(t));return dn(t,e.policies,e.articles,e.pages)}catch(e){return D(e instanceof Error?e.message:`Policy and FAQ search failed`,`Rephrase the query (e.g. 'return policy', 'shipping', 'contact') and try again.`)}};function un(e){let t=cn.flatMap(({type:t,patterns:n})=>n.some(t=>t.test(e))?[t]:[]);return t.length?t:/\bpolic(?:y|ies)\b/i.test(e)?[...Me]:[]}function dn(e,t,n,r){let i={policies:t,articles:n,pages:r};return t.length+n.length+r.length===0?w(`No policies or FAQ content found for "${e}".`,i,null,`The store may not have published this content. Ask the user to rephrase, or share the store's contact page if one exists.`):w(fn(e,t,n,r),i,pn(t,n,r),mn(t,n,r))}function fn(e,t,n,r){return`Found ${[t.length?`${t.length} polic${t.length===1?`y`:`ies`}`:null,r.length?`${r.length} page${r.length===1?``:`s`}`:null,n.length?`${n.length} article${n.length===1?``:`s`}`:null].filter(Boolean).join(`, `)||`no results`} for "${e}".`}function pn(e,t,n){let r=[e.length?`Policies: `+e.map(e=>`- ${e.title}: ${e.url}`).join(` `):null,n.length?`Pages: `+n.map(e=>`- ${e.title}: ${e.url}`).join(` `):null,t.length?`Articles: `+t.map(e=>`- ${e.title}: ${e.url}`).join(` `):null].filter(Boolean);return r.length?r.join(` `):null}function mn(e,t,n){return e.length?`Answer the user's question directly from the policy body text in the structured content. The body is the authoritative policy text — do not invent details that are not present.`:n.length||t.length?`The store has no matching policy. Share the relevant page or article URL, and answer from any page body or article excerpt in the structured content.`:`No matching policy or FAQ content was found. Ask the user to rephrase the question.`}let hn=async(e,t)=>{let n=gn(e);if(`error`in n)return n.error;let{handle:r,rawVariantId:i,selectedOptions:a}=n,o=await _n(r,i,a,t);if(`error`in o)return o.error;let{variantId:s,resolvedOptions:c}=o,l=kn(t.routes.product(r),r,s),u=!An(l);return u&&setTimeout(()=>t.navigate(l),0),vn({handle:r,variantId:s,url:l,navigated:u,resolvedOptions:c})};function gn(e){let t=e.catalog.variant_id,n=Cn(e.catalog.selected_options);if(t==null&&!n.length)return{error:D(`Provide either catalog.variant_id or catalog.selected_options.`,`For a specific variant, pass variant_id from get_product variants[].id. For a partial match like a color only, pass selected_options.`)};let r=wn(e.catalog.handle);return r?Dn(r)?{handle:r,rawVariantId:t??void 0,selectedOptions:n}:{error:D(`Product handle "${r}" is not valid.`,`Use a product handle from search_catalog, browse_store, or get_product.`)}:{error:D(`Product handle is required.`,`Pass catalog.handle, or call show_variant from a product page.`)}}async function _n(e,t,n,r){let i=t==null?``:X(t);if(i)return{variantId:i,resolvedOptions:void 0};if(n.length){let t=await yn(e,n,r);return`error`in t?t:{variantId:t.variantId,resolvedOptions:t.options}}return{error:D(`Product variant_id could not be resolved.`,`Call get_product to find an available variants[].id, then retry show_variant.`)}}function vn(e){let{handle:t,variantId:n,url:r,navigated:i,resolvedOptions:a}=e,o=a?.length?` (${a.map(e=>`${e.name}: ${e.value}`).join(`, `)})`:``;return E({summary:i?`Showing the selected variant${o}.`:`Already showing the selected variant${o}.`,navigated:i,destination:t,keyFields:`Variant id: ${n}`},{handle:t,variant_id:n,url:r,navigated:i,selected_options:a})}async function yn(e,t,n){try{let r=await V(e,{selected_options:t,routes:n.routes});return r?bn(r)||await xn(r,e,n)||{error:D(`No available variant matched the selected options.`,`Call get_product with the same selected_options to see available_options, then pick one and retry.`)}:{error:Sn(e)}}catch(e){return{error:D(e instanceof Error?e.message:`Failed to resolve variant from selected_options.`,`Call get_product first to inspect available variants, then retry show_variant with a variant_id.`)}}}function bn(e){let t=e.variants.filter(e=>e.availability.available)[0]??e.variants[0];return t?.id?{variantId:X(t.id),options:t.options}:null}async function xn(e,t,n){let r=e.available_options?.[0];if(!r?.length)return null;let i=await V(t,{selected_options:r,routes:n.routes}),a=i?.variants?.find(e=>e.availability.available)??i?.variants?.[0];return a?.id?{variantId:X(a.id),options:a.options}:null}function Sn(e){return D(`Product "${e}" was not found.`,`Call search_catalog or browse_store to find an available product.`)}function Cn(e){return e?.length?e.map(e=>({name:String(e?.name??``).trim(),value:String(e?.value??``).trim()})).filter(e=>e.name&&e.value):[]}function X(e){let t=String(e).trim();if(!t)return``;let n=t.startsWith(`gid://shopify/ProductVariant/`)?t.slice(29):t;return/^\d+$/.test(n)?n:``}function wn(e){return e?.trim()?Tn(e):En()}function Tn(e){let t=e?.trim();return t?v(t)||On(t):``}function En(){return typeof window>`u`?``:v(window.location.href)}function Dn(e){return!!e&&!/[/?#\\]/.test(e)&&e!==`.`&&e!==`..`}function On(e){try{return decodeURIComponent(e)}catch{return``}}function kn(e,t,n){let r=new URL(e,jn());if(r.searchParams.set(`variant`,n),En()===t){let e=Z().searchParams.get(`selling_plan`);e&&r.searchParams.set(`selling_plan`,e)}return r.pathname+r.search}function An(e){let t=Z();return t.pathname+t.search===e}function Z(){return typeof window>`u`?new URL(`https://shopify.local/`):new URL(window.location.href)}function jn(){return typeof window>`u`?`https://shopify.local`:window.location.origin}let Mn=async(e,t)=>{let n=e.cart?.line_items;if(!Array.isArray(n)||n.length===0)return D(`No line_items provided.`,`Call update_cart with cart.line_items.`);let r=n.slice(0,10);try{let e=await Promise.all(r.map((e,t)=>Pn(e??{},t))),n=e.filter(Bn);return n.length?In(n,e,r.length):await Nn(e.filter(Vn),t)}catch(e){return D(e instanceof Error?e.message:`Cart update failed`,`Call get_cart to verify cart state, then retry update_cart with explicit line_items[].id or line_items[].item.id.`)}};async function Nn(e,t){let n=Un(e);if(n&&Wn(n))return Kn();let r=await O().updateCart({lines:e.map(e=>e.type===`update`?{id:e.id,quantity:e.quantity}:{merchandiseId:e.merchandiseId,quantity:e.quantity})});ge(r),n&&Gn(n);let i=_e(r),a=r.cart??{},o=N(a.cost?.totalAmount),s=await Ln(e.filter(Q),a.id,t.routes);return T(zn(e,A(a),o,i),{updated:!0,item_count:A(a),total_price:o,line_items:s,warnings:i.length?i:void 0},`This change has ALREADY been applied — the item_count and total in this result are the authoritative post-update cart state. Do NOT call update_cart again for this request: adds are cumulative, so repeating the call adds duplicate items or re-applies quantity changes. If you need to confirm, read the values in this result instead of re-running the mutation.`)}async function Pn(e,t){let n=Fn(e.quantity,!!e.id);if(e.id)return{type:`update`,id:e.id,quantity:n};if(e.item?.id)return{type:`add`,merchandiseId:e.item.id,quantity:n};let r=await Be({handle:e.handle,query:e.query});return r?{type:`add`,merchandiseId:r.variant.merchandise_id,quantity:n,productTitle:r.product.title,variantTitle:r.variant.title}:{type:`unresolved`,item:t+1,reason:e.handle?`Could not resolve product handle "${e.handle}".`:e.query?`Could not find a product for query "${e.query}".`:`Missing item.id, handle, or query.`,query:e.query,handle:e.handle}}function Fn(e,t){let n=Number(e);return Number.isFinite(n)?Math.max(+!t,Math.floor(n)):1}function In(e,t,n){let r=t.filter(Q),i=e.map(e=>`- Item ${e.item}: ${e.reason}`).join(` `);return w(`Need clarification for ${e.length} of ${n} line_item${n===1?``:`s`}. Nothing changed.`,{updated:!1,unresolved_items:e,resolved_items:r.map(Rn)},i,`Call search_catalog or get_product to find explicit product or variant ids, then call update_cart again. For specific variant requests, prefer line_items[].item.id from get_product variants[].id.`)}async function Ln(e,t,n){let r=e.map(Rn);if(!t||e.length===0)return r;let i;try{i=await ze(t,n)}catch{return r}if(!i)return r;let a=new Map;for(let e of i.line_items)e.item.id&&a.set(e.item.id,e);return e.map((e,t)=>{let n=a.get(e.merchandiseId);return n?{item:n.item,quantity:n.quantity,requested_quantity:e.quantity}:r[t]})}function Rn(e){return{item:{id:e.merchandiseId,title:e.productTitle??``,variant_title:e.variantTitle??``,handle:``,url:``,image:``,unit_price:null},quantity:e.quantity,requested_quantity:e.quantity}}function zn(e,t,n,r){let i=e.filter(Q),a=e.filter(Hn),o=i.reduce((e,t)=>e+t.quantity,0),s=[];i.length&&s.push(`Added ${o} item${o===1?``:`s`} across ${i.length} product${i.length===1?``:`s`}`),a.length&&s.push(`updated ${a.length} line${a.length===1?``:`s`}`);let c=`Cart now has ${t} item${t===1?``:`s`}${n?` totaling ${P(n)}`:``}.`,l=r.length?` Warnings: ${r.join(`; `)}.`:``;return`${s.join(` and `)}. ${c}${l}`}function Bn(e){return e.type===`unresolved`}function Vn(e){return e.type===`add`||e.type===`update`}function Q(e){return e.type===`add`}function Hn(e){return e.type===`update`}let $=null;function Un(e){if(!e.some(Q))return null;let t=e.map(e=>e.type===`add`?`a:${e.merchandiseId}:${e.quantity}`:`u:${e.id}:${e.quantity}`).toSorted();return JSON.stringify(t)}function Wn(e){return $!==null&&$.signature===e&&Date.now()-$.at<5e3}function Gn(e){$={signature:e,at:Date.now()}}function Kn(){return w(`An identical add was just applied — the cart already includes these items, so I did not add them again (this prevents accidental duplicates).`,{updated:!1,deduped:!0},null,`If the shopper truly wants MORE of the same item, call update_cart again with a higher quantity, or call get_cart and set the line's quantity by line_items[].id. Otherwise do NOT repeat this call — the previous update already succeeded.`)}let qn={browse_store:Ct,cancel_cart:jt,proceed_to_checkout:Mt,get_cart:Pt,get_product:Ht,manage_orders:Zt,search_catalog:$t,search_shop_policies_and_faqs:ln,show_variant:hn,update_cart:Mn},Jn=Symbol.for(`shopify.webmcp.registered`),Yn=Object.values(ce).map(e=>({...e,execute:qn[e.name]}));function Xn(){let e=Qn();if(!e||$n())return!1;let t={routes:te,navigate:Zn},n=[];for(let r of Yn){let i=tr(r,t);n.push(e.registerTool(i))}return er(),Promise.allSettled(n),!0}function Zn(e){let t=window.Shopify?.navigate;if(t)return t(e);window.location.href=e}function Qn(){return typeof document<`u`&&`modelContext`in document?document.modelContext??null:typeof navigator<`u`&&`modelContext`in navigator?navigator.modelContext??null:null}function $n(){return typeof window>`u`?!1:Reflect.get(window,Jn)===!0}function er(){typeof window>`u`||Reflect.set(window,Jn,!0)}function tr(e,t){let{execute:n,...r}=e;return{...r,execute:ee(e.name,e=>n(e,t))}}(function(){typeof window>`u`||Xn()})()})(); //# sourceMappingURL=webmcp-0.1.0.js.map